package com.joe.core;

import com.joe.annotations.Mapper;
import com.joe.utils.PathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by joe on 2018/11/25
 * <p>
 * Jatis上下文对象
 * 管理项目中所有mapper对象
 */
public class JatisContext {
    private static final Logger logger = LoggerFactory.getLogger(JatisContext.class);

    private static final ClassLoader classLoader = JatisContext.class.getClassLoader();

    private static Map<Class, Object> MAPPER_CACHE = null;

    private static final String BASE_PATH = PathUtils.getRuntimeResourcePath();

    public static void init() throws ClassNotFoundException {
        if (MAPPER_CACHE == null) {
            MAPPER_CACHE = new HashMap<>();
        }
        loadDao(new File(BASE_PATH));
    }

    /**
     * 获取Dao
     */
    public static <T> T getDao(Class<T> clazz) {
        if (MAPPER_CACHE == null) {
            try {
                init();
            } catch (Exception e) {
                logger.error("JatisContext init failed!", e);
            }
        }
        return (T) MAPPER_CACHE.get(clazz);
    }

    /**
     * 扫描加载所有dao
     */
    private static void loadDao(File file) throws ClassNotFoundException {
        if (file.isDirectory()) {
            for (File fi : file.listFiles()) {
                loadDao(fi);
            }
            return;
        }
        String filePath = file.getPath();
        if (!filePath.endsWith(".class")) {
            return;
        }
        int sufIndex = filePath.lastIndexOf(".");
        String classPath = filePath.substring(0, sufIndex);

        String[] classPathArr = PathUtils.pathSplit(classPath);

        StringBuilder sb = new StringBuilder();
        for (int i = PathUtils.pathSplit(BASE_PATH).length; i < classPathArr.length; i++) {
            sb.append(classPathArr[i]);
            if (i < (classPathArr.length - 1)) {
                sb.append(".");
            }
        }
        Class clazz = Class.forName(sb.toString());
        if (!clazz.isInterface() || clazz.isAnnotation()) {
            return;
        }
        Mapper mapper = (Mapper) clazz.getAnnotation(Mapper.class);
        if (mapper == null) {
            return;
        }
        MAPPER_CACHE.put(clazz, Proxy.newProxyInstance(classLoader, new Class[]{clazz}, new ProxyHandler()));
    }

}
